import { Injectable } from '@nestjs/common';
import { InjectConnection } from '@nestjs/mongoose';
import { Connection } from 'mongoose';
import { InsertOneResult, DeleteResult, UpdateResult, ObjectId, Document, InsertManyResult } from 'mongodb'
import { Util } from '@/common/util/util.service'
import { WhereJsonDecorator, SortArrDecorator, ForeignDecorator, FormDataDecorator } from './base.Decorator'

interface SortItem {
    name: string;
    type: 'desc' | 'asc';
}

type SortObject = Record<string, 1 | -1>;

type AggregationStage = {
    dbName?: string;
    localKey?: string;
    foreignKey?: string;
    as?: string;
    unwind?: boolean;
    limit?: number;
    whereJson?: object;
    fieldJson?: object;
    sortArr?: SortItem[] | SortObject;
    foreignDB?: AggregationStage[];
    // 其他聚合操作符...
};

type Data = {
    formData: Object;
    columns: any[];
    pageIndex: number;
    pageSize: number;
}

interface Params {
    dbName: string;
    whereJson?: object;
    pageSize?: number;
    pageIndex?: number;
    getMain?: boolean,
    getCount?: boolean;
    fieldJson?: Record<string, any>;
    limit?: number;
    dataJson: Record<string, any>;
    cancelAddTime?: boolean;
    cancelAddTimeStr?: boolean;
    id?: string,
    sortArr?: SortItem[] | SortObject;
    returnDocument?: 'after' | 'before',
    foreignDB?: AggregationStage[];
    data?: Data;
    // 其他参数...
}


@Injectable()
export class BaseDao {
    constructor(
        @InjectConnection() private readonly connection: Connection,
        private readonly util: Util,
    ) { }

    async adds({ dbName, dataJson, cancelAddTime = false, cancelAddTimeStr = false }): Promise<InsertManyResult> {
        const dataJsons = dataJson.map(item => {
            return {
                ...item,
                ...(!cancelAddTime ? { _add_time: Date.now() } : {}),
                ...(!cancelAddTimeStr && !cancelAddTime ? { _add_time_str: this.util.formatTimestamp(Date.now(), 'yyyy-MM-dd hh:mm:ss') } : {}),
            }
        })
        return await this.connection.collection(dbName).insertMany(dataJsons);
    }


    async add({ dbName, dataJson, cancelAddTime = false, cancelAddTimeStr = false }: Pick<Params, 'dbName' | 'dataJson' | 'cancelAddTime' | 'cancelAddTimeStr'>): Promise<InsertOneResult> {
        dataJson = {
            ...dataJson,
            ...(!cancelAddTime ? { _add_time: Date.now() } : {}),
            ...(!cancelAddTimeStr && !cancelAddTime ? { _add_time_str: this.util.formatTimestamp(Date.now(), 'yyyy-MM-dd hh:mm:ss') } : {}),
        }
        return await this.connection.collection(dbName).insertOne(dataJson);
    }

    @WhereJsonDecorator
    async del({ dbName, whereJson }: Pick<Params, 'dbName' | 'whereJson'>): Promise<DeleteResult> {
        return await this.connection.collection(dbName).deleteMany(whereJson);
    }

    async deleteById({ dbName, id }: Pick<Params, 'dbName' | 'id'>): Promise<DeleteResult> {
        return await this.connection.collection(dbName).deleteMany({ _id: new ObjectId(id) });
    }

    @WhereJsonDecorator
    async update({ dbName, whereJson, dataJson }: Pick<Params, 'dbName' | 'whereJson' | 'dataJson'>): Promise<UpdateResult> {
        return await this.connection.collection(dbName).updateMany(whereJson, { $set: dataJson });
    }

    @WhereJsonDecorator
    async updateById({ dbName, id, dataJson }: Pick<Params, 'dbName' | 'id' | 'dataJson'>): Promise<UpdateResult> {
        console.log('id', id)
        console.log('dataJson', dataJson)
        return await this.connection.collection(dbName).updateOne({ _id: new ObjectId(id) }, { $set: dataJson });
    }

    @WhereJsonDecorator
    async updateAndReturn({ dbName, whereJson, dataJson, returnDocument = 'after' }: Pick<Params, 'dbName' | 'whereJson' | 'dataJson' | 'returnDocument'>): Promise<Document> {
        return await this.connection.collection(dbName).findOneAndUpdate(whereJson, { $set: dataJson }, { returnDocument });
    }

    @WhereJsonDecorator
    async setById({ dbName, dataJson, id }: Pick<Params, 'dbName' | 'dataJson' | 'id'>): Promise<Document> {
        return await this.connection.collection(dbName).updateOne({ _id: new ObjectId(id) }, { $set: dataJson }, { upsert: true });
    }

    @WhereJsonDecorator
    async findByWhereJson({ dbName, whereJson, fieldJson, }: Pick<Params, 'dbName' | 'whereJson' | 'fieldJson'>): Promise<Document> {
        console.log('whereJson', whereJson)
        return await this.connection.collection(dbName).findOne(whereJson, { projection: fieldJson });
    }

    @WhereJsonDecorator
    async findById({ dbName, id, fieldJson }: Pick<Params, 'dbName' | 'id' | 'fieldJson'>): Promise<Document> {
        return await this.connection.collection(dbName).findOne({ _id: new ObjectId(id) }, { projection: fieldJson });
    }

    @FormDataDecorator
    async getTableData({ dbName, data, whereJson, sortArr = { _add_time: 1 }, foreignDB, getMain = false, getCount = true }: Pick<Params, 'dbName' | 'getCount' | 'data' | 'whereJson' | 'sortArr'|'getMain' | 'foreignDB'>): Promise<Document[]> {
        // console.log("参数whereJson", whereJson)
        const { pageIndex = 1, pageSize = 10 } = data;
        if (foreignDB) {
            return await this.selects({ dbName, whereJson, sortArr, foreignDB, getMain,getCount });
        } else {
            return await this.select({ dbName, whereJson, sortArr, pageIndex, pageSize });
        }

    }

    @SortArrDecorator
    @WhereJsonDecorator
    async select({ dbName, whereJson, fieldJson, pageSize = 10, pageIndex = 1, sortArr, getMain = false, getCount = true }: Pick<Params, 'dbName' | 'fieldJson' | 'pageSize' | 'whereJson' | 'pageIndex' | 'sortArr' | 'getCount' | 'getMain'>): Promise<Document[]> {

        const skip = pageSize * (pageIndex - 1);

        // 创建游标
        const cursor = this.connection
            .collection(dbName)
            .find(whereJson, { projection: fieldJson })
            .sort(sortArr as SortObject)
            .skip(skip)
            .limit(pageSize);

        const rows: any[] = [];
        // 遍历游标，逐行读取数据
        for await (const doc of cursor) {
            rows.push(doc);
        }

        let total = 0;
        if (getCount) {
            total = await this.connection.collection(dbName).countDocuments(whereJson);
        }

        const hasMore = getCount ? total > pageSize * pageIndex : rows.length === pageSize;
        const result: any = {
            pagination: {
                pageIndex,
                pageSize,
            },
            rows,
            hasMore,
        };

        if (getCount) {
            result.total = total;
        }

        if (getMain) {
            return result.rows;
        }

        return result;
    }

    @SortArrDecorator
    @WhereJsonDecorator
    async selectRows({ dbName, whereJson, fieldJson, pageSize = 10, pageIndex = 1, sortArr, getMain = false }: Pick<Params, 'dbName' | 'fieldJson' | 'pageSize' | 'whereJson' | 'pageIndex' | 'sortArr' | 'getCount' | 'getMain'>): Promise<Document[]> {

        const skip = pageSize * (pageIndex - 1); // 计算跳过的文档数
        console.log('skip', skip)
        console.log('limit', pageSize)
        console.log('sortArr', sortArr)
        const query = this.connection.collection(dbName).find(whereJson, { projection: fieldJson }).sort(sortArr as SortObject).skip(skip)

        // 兼容查找全部
        if (pageSize > 0 && pageIndex > 0) {
            query.limit(pageSize)
        }

        const rows = await query.toArray();
        // 如果需要获取记录总数
        let total = await this.connection.collection(dbName).countDocuments(whereJson);
        // 是否有下一页数据
        const hasMore = total > pageSize * pageIndex
        const result: any = {
            pageIndex,
            pageSize,
            rows,
            hasMore,
            total
        };

        if ((pageIndex === 0 && pageSize === 0) || getMain) {
            // 只返回 rows 数据
            return result.rows;
        }

        return result;
    }

    @SortArrDecorator
    @WhereJsonDecorator
    @ForeignDecorator
    async selects({ dbName, whereJson, limit, sortArr = { _add_time: 1 }, fieldJson, foreignDB, getCount, pageIndex = 1, pageSize = 10, getMain = false }: Pick<Params, 'dbName' | 'whereJson' | 'limit' | 'sortArr' | 'fieldJson' | 'foreignDB' | 'getCount' | 'pageIndex' | 'pageSize' | 'getMain'>): Promise<Document[]> {

        const skip = (pageIndex - 1) * pageSize;

        const defaultForeignDB = [
            { $sort: sortArr as SortObject }, // 根据条件过滤文档
            { $match: whereJson }, // 根据条件过滤文档
            { $project: fieldJson },
            { $limit: limit },
            ...(pageSize ? [{ $skip: skip }, { $limit: pageSize + 1 }] : []),
        ].filter(item => {
            // 判断对象的属性值是否为空对象
            return !Object.values(item).every(value =>
                (typeof value === 'object' && Object.keys(value).length === 0) || value === undefined
            );
        });
        const data = await this.connection.collection(dbName).aggregate([
            ...defaultForeignDB,
            ...foreignDB,
        ]).toArray();

        const hasMore = data.length > pageSize; // 判断是否有下一页数据
    

        let result: any = { rows: data, hasMore }; // 初始化结果对象

        if (getCount) {
            // 统计总数
            const total = await this.connection
                .collection(dbName)
                .countDocuments(whereJson);
            result.total = total;
        }

        if (getMain) {
            // 仅返回 rows 数组
            if (result.rows.length === 1) {
            // 如果只有一个结果，直接返回单个对象
                return result.rows[0] as Document[];  // 强制转换为 T 类型
            }
            return result.rows;
        }

        return result

        
        // // 如果有多个结果，返回数组
        // return data;
    }

    @WhereJsonDecorator
    async count({ dbName, whereJson }: Pick<Params, 'dbName' | 'whereJson'>): Promise<number> {

        const pipeline = [
            { $match: whereJson }, // 根据条件过滤文档
            { $group: { _id: "$groupField", count: { $sum: 1 } } } // 按 groupField 分组并统计数量
        ];

        return await this.connection.collection(dbName).countDocuments(whereJson);
    }
}
